home *** CD-ROM | disk | FTP | other *** search
- /*===========================================================================*
- * iframe.c *
- * *
- * Procedures concerned with the I-frame encoding *
- * *
- * EXPORTED PROCEDURES: *
- * GenIFrame *
- * SetSlicesPerFrame *
- * SetBlocksPerSlice *
- * SetIQScale *
- * ResetIFrameStats *
- * ShowIFrameSummary *
- * EstimateSecondsPerIFrame *
- * EncodeYDC *
- * EncodeCDC *
- * *
- *===========================================================================*/
-
- /*
- * Copyright (c) 1993 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
- /*
- * $Header: /n/picasso/users/keving/encode/src/RCS/iframe.c,v 1.6 1993/07/22 22:23:43 keving Exp keving $
- * $Log: iframe.c,v $
- * Revision 1.6 1993/07/22 22:23:43 keving
- * nothing
- *
- * Revision 1.5 1993/06/30 20:06:09 keving
- * nothing
- *
- * Revision 1.4 1993/06/03 21:08:08 keving
- * nothing
- *
- * Revision 1.3 1993/03/04 22:24:06 keving
- * nothing
- *
- * Revision 1.2 1993/02/19 18:10:02 keving
- * nothing
- *
- * Revision 1.1 1993/02/18 22:56:39 keving
- * nothing
- *
- *
- */
-
-
- /*==============*
- * HEADER FILES *
- *==============*/
-
- /* @@@ Fake up 'times' interface under OS/2, Andy Key */
- #ifdef OS2
- #include "os2port.h"
- #else
- #include <sys/times.h>
- #endif
- #include "all.h"
- #include "mtypes.h"
- #include "frames.h"
- #ifdef OS2
- /* @@@ FAT 8.3 convention */
- #include "prototyp.h"
- #else
- #include "prototypes.h"
- #endif
- #include "mpeg.h"
- #include "param.h"
- #include "mheaders.h"
- #include "fsize.h"
- #include "parallel.h"
- #include "postdct.h"
-
-
- /*==================*
- * STATIC VARIABLES *
- *==================*/
-
- static int numBlocks = 0;
- static int numBits;
- static int numFrames = 0;
- static int numFrameBits = 0;
- static int32 totalTime = 0;
- static float totalSNR = 0.0;
- static float totalPSNR = 0.0;
-
-
- /*==================*
- * GLOBAL VARIABLES *
- *==================*/
-
- int qscaleI;
- int slicesPerFrame;
- int blocksPerSlice;
- int fCode;
- boolean printSNR = FALSE;
- boolean decodeRefFrames = FALSE;
-
-
- /*=====================*
- * EXPORTED PROCEDURES *
- *=====================*/
-
-
- /*===========================================================================*
- *
- * SetFCode
- *
- * set the forward_f_code and backward_f_code according to the search
- * range. Must be called AFTER pixelFullSearch and searchRange have
- * been initialized. Irrelevant for I-frames, but computation is
- * negligible (done only once, as well)
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: fCode
- *
- *===========================================================================*/
- void
- SetFCode()
- {
- int range;
-
- if ( pixelFullSearch ) {
- range = searchRange;
- } else {
- range = searchRange*2;
- }
-
- if ( range < 256 ) {
- if ( range < 64 ) {
- if ( range < 32 ) {
- fCode = 1;
- } else {
- fCode = 2;
- }
- } else {
- if ( range < 128 ) {
- fCode = 3;
- } else {
- fCode = 4;
- }
- }
- } else {
- if ( range < 1024 ) {
- if ( range < 512 ) {
- fCode = 5;
- } else {
- fCode = 6;
- }
- } else {
- if ( range < 2048 ) {
- fCode = 7;
- } else {
- fprintf(stdout, "ERROR: INVALID SEARCH RANGE!!!\n");
- exit(1);
- }
- }
- }
- }
-
-
- /*===========================================================================*
- *
- * SetSlicesPerFrame
- *
- * set the number of slices per frame
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: slicesPerFrame
- *
- *===========================================================================*/
- void
- SetSlicesPerFrame(number)
- int number;
- {
- slicesPerFrame = number;
- }
-
-
- /*===========================================================================*
- *
- * SetBlocksPerSlice
- *
- * set the number of blocks per slice, based on slicesPerFrame
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: blocksPerSlice
- *
- *===========================================================================*/
- void
- SetBlocksPerSlice()
- {
- int totalBlocks;
-
- totalBlocks = (Fsize_y/16)*(Fsize_x/16);
-
- if ( slicesPerFrame > totalBlocks ) {
- blocksPerSlice = 1;
- } else {
- blocksPerSlice = totalBlocks/slicesPerFrame;
- }
- }
-
-
- /*===========================================================================*
- *
- * SetIQScale
- *
- * set the I-frame Q-scale
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: qscaleI
- *
- *===========================================================================*/
- void
- SetIQScale(qI)
- int qI;
- {
- qscaleI = qI;
- }
-
-
- /*===========================================================================*
- *
- * GenIFrame
- *
- * generate an I-frame; appends result to bb
- *
- * RETURNS: I-frame appended to bb
- *
- * SIDE EFFECTS: none
- *
- *===========================================================================*/
- void
- GenIFrame(bb, current)
- BitBucket *bb;
- MpegFrame *current;
- {
- register int x, y;
- register int index;
- FlatBlock fb[6];
- Block dec[6];
- int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
- int totalBits;
- int totalFrameBits;
- struct tms timeBuffer;
- int32 startTime, endTime;
- int frameBlocks;
- float snr[3], psnr[3];
-
- /* set-up for statistics */
- numFrames++;
- totalFrameBits = bb->cumulativeBits;
- times(&timeBuffer);
- startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
-
- Frame_AllocBlocks(current);
- BlockifyFrame(current);
-
- DBG_PRINT(("Generating iframe\n"));
-
- Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCode);
- Mhead_GenSliceHeader(bb, 1, qscaleI, NULL, 0);
-
- if ( referenceFrame == DECODED_FRAME ) {
- Frame_AllocDecoded(current, TRUE);
- } else if ( printSNR ) {
- Frame_AllocDecoded(current, FALSE);
- }
-
- y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
- totalBits = bb->cumulativeBits;
- frameBlocks = 0;
- for (y = 0; y < Fsize_y / 8; y += 2) {
- for (x = 0; x < Fsize_x / 8; x += 2) {
- /* DCT this macroblock */
- mp_fwd_dct_block(current->y_blocks[y][x]);
- mp_fwd_dct_block(current->y_blocks[y][x+1]);
- mp_fwd_dct_block(current->y_blocks[y+1][x]);
- mp_fwd_dct_block(current->y_blocks[y+1][x+1]);
- mp_fwd_dct_block(current->cr_blocks[y>>1][x>>1]);
- mp_fwd_dct_block(current->cb_blocks[y>>1][x>>1]);
-
- if ( (frameBlocks % blocksPerSlice == 0) && (frameBlocks != 0) ) {
- /* create a new slice */
- Mhead_GenSliceEnder(bb);
- Mhead_GenSliceHeader(bb, 1+(y/2), qscaleI, NULL, 0);
- y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
-
- GEN_I_BLOCK(I_FRAME, current, bb, 1+(x/2), qscaleI);
- } else {
- GEN_I_BLOCK(I_FRAME, current, bb, 1, qscaleI);
- }
-
- if ( decodeRefFrames ) {
- /* need to decode block we just encoded */
- Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleI, TRUE);
- Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleI, TRUE);
- Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleI, TRUE);
- Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleI, TRUE);
- Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleI, TRUE);
- Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleI, TRUE);
-
- /* now, reverse the DCT transform */
- for ( index = 0; index < 6; index++ ) {
- j_rev_dct((int16 *)dec[index]);
- }
-
- /* now, unblockify */
- BlockToData(current->decoded_y, dec[0], y, x);
- BlockToData(current->decoded_y, dec[1], y, x+1);
- BlockToData(current->decoded_y, dec[2], y+1, x);
- BlockToData(current->decoded_y, dec[3], y+1, x+1);
- BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
- BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
- }
-
- numBlocks++;
- frameBlocks++;
- }
- }
-
- if ( printSNR ) {
- ComputeSNR(current->orig_y, current->decoded_y, Fsize_y, Fsize_x,
- &snr[0], &psnr[0]);
- ComputeSNR(current->orig_cb, current->decoded_cb, Fsize_y/2, Fsize_x/2,
- &snr[1], &psnr[1]);
- ComputeSNR(current->orig_cr, current->decoded_cr, Fsize_y/2, Fsize_x/2,
- &snr[2], &psnr[2]);
-
- totalSNR += snr[0];
- totalPSNR += psnr[0];
- }
-
- if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
- if ( remoteIO ) {
- SendDecodedFrame(current);
- } else {
- WriteDecodedFrame(current);
- }
-
- /* now, tell decode server it is ready */
- NotifyDecodeServerReady(current->id);
- }
-
- numBits += (bb->cumulativeBits-totalBits);
-
- DBG_PRINT(("End of frame\n"));
-
- Mhead_GenSliceEnder(bb);
-
- times(&timeBuffer);
- endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
- totalTime += (endTime-startTime);
-
- numFrameBits += (bb->cumulativeBits-totalFrameBits);
-
- if ( (! childProcess) && frameSummary ) {
- fprintf(stdout, "FRAME %d (I): %ld seconds\n",
- current->id, (long)((endTime-startTime)/60));
- if ( printSNR ) {
- fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\tPSNR: %.1f\t%.1f\t%.1f\n",
- current->id, snr[0], snr[1], snr[2],
- psnr[0], psnr[1], psnr[2]);
- }
- }
- }
-
-
- /*===========================================================================*
- *
- * ResetIFrameStats
- *
- * reset the I-frame statistics
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: none
- *
- *===========================================================================*/
- void
- ResetIFrameStats()
- {
- numBlocks = 0;
- numBits = 0;
- numFrames = 0;
- numFrameBits = 0;
- totalTime = 0;
- }
-
-
- /*===========================================================================*
- *
- * ShowIFrameSummary
- *
- * prints out statistics on all I-frames
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS: none
- *
- *===========================================================================*/
- void
- ShowIFrameSummary(inputFrameBits, totalBits, fpointer)
- int inputFrameBits;
- int32 totalBits;
- FILE *fpointer;
- {
- if ( numFrames == 0 ) {
- return;
- }
-
- fprintf(fpointer, "-------------------------\n");
- fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
- fprintf(fpointer, "-------------------------\n");
-
- fprintf(fpointer, " Blocks: %5d (%6d bits) (%5d bpb)\n",
- numBlocks, numBits, numBits/numBlocks);
- fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf) (%2.1f%% of total)\n",
- numFrames, numFrameBits, numFrameBits/numFrames,
- 100.0*(float)numFrameBits/(float)totalBits);
- fprintf(fpointer, " Compression: %3d:1\n",
- numFrames*inputFrameBits/numFrameBits);
- if ( printSNR )
- fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n",
- totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
- fprintf(fpointer, " Seconds: %9ld (%9ld spf) (%9ld bps)\n",
- (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
- (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
- }
-
-
- /*===========================================================================*
- *
- * EstimateSecondsPerIFrame
- *
- * estimates the number of seconds required per I-frame
- *
- * RETURNS: seconds (floating point value)
- *
- * SIDE EFFECTS: none
- *
- *===========================================================================*/
- float
- EstimateSecondsPerIFrame()
- {
- return (float)totalTime/(60.0*(float)numFrames);
- }
-
-
- /*===========================================================================*
- *
- * EncodeYDC
- *
- * Encode the DC portion of a DCT of a luminance block
- *
- * RETURNS: result appended to bb
- *
- * SIDE EFFECTS: updates pred_term
- *
- *===========================================================================*/
- void
- EncodeYDC(dc_term, pred_term, bb)
- int32 dc_term;
- int32 *pred_term;
- BitBucket *bb;
- {
- int ydiff, ydiff_abs;
-
- ydiff = (dc_term - (*pred_term));
- if (ydiff > 255) {
- ydiff = 255;
- } else if (ydiff < -255) {
- ydiff = -255;
- }
-
- ydiff_abs = ABS(ydiff);
-
- if (ydiff_abs == 0) {
- Bitio_Write(bb, 0x4, 3);
- } else if (ydiff_abs & 0x80) {
- Bitio_Write(bb, 0x7e, 7);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 8);
- } else
- Bitio_Write(bb, ~ydiff_abs, 8);
- } else if (ydiff_abs & 0x40) {
- Bitio_Write(bb, 0x3e, 6);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 7);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 7);
- }
- } else if (ydiff_abs & 0x20) {
- Bitio_Write(bb, 0x1e, 5);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 6);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 6);
- }
- } else if (ydiff_abs & 0x10) {
- Bitio_Write(bb, 0xe, 4);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 5);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 5);
- }
- } else if (ydiff_abs & 0x08) {
- Bitio_Write(bb, 0x6, 3);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 4);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 4);
- }
- } else if (ydiff_abs & 0x04) {
- Bitio_Write(bb, 0x5, 3);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 3);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 3);
- }
- } else if (ydiff_abs & 0x02) {
- Bitio_Write(bb, 0x1, 2);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 2);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 2);
- }
- } else if (ydiff_abs & 0x01) {
- Bitio_Write(bb, 0x0, 2);
- if (ydiff > 0) {
- Bitio_Write(bb, ydiff_abs, 1);
- } else {
- Bitio_Write(bb, ~ydiff_abs, 1);
- }
- } else {
- fprintf(stderr, "ERROR in EncodeYDC\n");
- exit(1);
- }
-
- (*pred_term) += ydiff;
- }
-
-
- /*===========================================================================*
- *
- * EncodeCDC
- *
- * Encode the DC portion of a DCT of a chrominance block
- *
- * RETURNS: result appended to bb
- *
- * SIDE EFFECTS: updates pred_term
- *
- *===========================================================================*/
- void
- EncodeCDC(dc_term, pred_term, bb)
- int32 dc_term;
- int32 *pred_term;
- BitBucket *bb;
- {
- int cdiff, cdiff_abs;
-
- cdiff = (dc_term - (*pred_term));
- if (cdiff > 255) {
- cdiff = 255;
- } else if (cdiff < -255) {
- cdiff = -255;
- }
-
- cdiff_abs = ABS(cdiff);
-
- if (cdiff_abs == 0) {
- Bitio_Write(bb, 0x0, 2);
- } else if (cdiff_abs & 0x80) {
- Bitio_Write(bb, 0xfe, 8);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 8);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 8);
- }
- } else if (cdiff_abs & 0x40) {
- Bitio_Write(bb, 0x7e, 7);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 7);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 7);
- }
- } else if (cdiff_abs & 0x20) {
- Bitio_Write(bb, 0x3e, 6);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 6);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 6);
- }
- } else if (cdiff_abs & 0x10) {
- Bitio_Write(bb, 0x1e, 5);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 5);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 5);
- }
- } else if (cdiff_abs & 0x08) {
- Bitio_Write(bb, 0xe, 4);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 4);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 4);
- }
- } else if (cdiff_abs & 0x04) {
- Bitio_Write(bb, 0x6, 3);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 3);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 3);
- }
- } else if (cdiff_abs & 0x02) {
- Bitio_Write(bb, 0x2, 2);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 2);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 2);
- }
- } else if (cdiff_abs & 0x01) {
- Bitio_Write(bb, 0x1, 2);
- if (cdiff > 0) {
- Bitio_Write(bb, cdiff_abs, 1);
- } else {
- Bitio_Write(bb, ~cdiff_abs, 1);
- }
- } else {
- fprintf(stderr, "ERROR in EncodeCDC\n");
- exit(1);
- }
-
- (*pred_term) += cdiff;
- }
-
-
- void
- ComputeSNR(origData, newData, ySize, xSize, snr, psnr)
- register uint8 **origData;
- register uint8 **newData;
- int ySize;
- int xSize;
- float *snr;
- float *psnr;
- {
- register int32 tempInt;
- register int y, x;
- int32 varOrig = 0;
- int32 varDiff = 0;
-
- /* compute Y-plane SNR */
- for ( y = 0; y < ySize; y++ ) {
- for ( x = 0; x < xSize; x++ ) {
- tempInt = origData[y][x];
- varOrig += (tempInt*tempInt);
- }
- }
-
- for ( y = 0; y < ySize; y++ ) {
- for ( x = 0; x < xSize; x++ ) {
- tempInt = (origData[y][x]-newData[y][x]);
- varDiff += (tempInt*tempInt);
- }
- }
-
- *snr = 10.0*log10((double)varOrig/(double)varDiff);
- *psnr = 20.0*log10(255.0/sqrt((double)varDiff/(double)(ySize*xSize)));
- }
-
-
- void
- WriteDecodedFrame(frame)
- MpegFrame *frame;
- {
- FILE *fpointer;
- char fileName[256];
- int width, height;
- register int y;
-
- /* need to save decoded frame to disk because it might be accessed
- by another process */
-
- width = Fsize_x;
- height = Fsize_y;
-
- sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
- fprintf(stdout, "outputting to %s\n", fileName);
- fflush(stdout);
-
- /* @@@ Open binary mode for OS/2, Andy Key */
- #ifdef OS2
- fpointer = fopen(fileName, "wb");
- #else
- fpointer = fopen(fileName, "w");
- #endif
-
- for ( y = 0; y < height; y++ ) {
- fwrite(frame->decoded_y[y], 1, width, fpointer);
- }
-
- for (y = 0; y < height / 2; y++) { /* U */
- fwrite(frame->decoded_cb[y], 1, width / 2, fpointer);
- }
-
- for (y = 0; y < height / 2; y++) { /* V */
- fwrite(frame->decoded_cr[y], 1, width / 2, fpointer);
- }
-
- fclose(fpointer);
- }
-